﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

using FairyGUI;
using System;

public class BezierTween
{
	public int id;
	public Vector2 startPos;
	public Vector2 endPos;
	public Vector2 control1;
	public GObject target;
	public float maxTime;
	public float delay;
	public float accelerate = 1;
	private float time;
	private System.Action complete;
	public bool isComplete;
	public EaseType easeType = EaseType.Linear;
	public void Reset()
	{
		time = 0;
		complete = null;
		isComplete = false;
		target = null;
	}
	public BezierTween SetDelay(float delay)
	{
		this.delay = delay;
		return this;
	}
	public BezierTween SetAccelerate(float acc)
	{
		accelerate = acc;
		return this;
	}
	public BezierTween OnComplete(System.Action complete)
	{
		this.complete = complete;
		return this;
	}
	public BezierTween SetEaseType(EaseType type)
	{
		easeType = type;
		return this;
	}
	private float GetT(float dt)
	{
		time += dt;
		float t = time / maxTime;
		t = Mathf.Pow(t ,accelerate);
		return t;
	}
	public void Update(float dt)
	{
		if (isComplete) return;
		if (target == null) return;
		if (delay > 0)
		{
			delay -= dt;
			return;
		}
		float t = GetT(dt);
		if( t>= 1)
		{
			isComplete = true;
			t = 1;
		}
		
		
		Vector2 pos = (1 - t) * (1 - t) * startPos + 2 * t * (1 - t) * control1 + t * t * endPos;
		target.SetXY(pos.x, pos.y);
		if (isComplete)
		{
			complete?.Invoke();
		}
	}
}
public class BezierTweenMgr : MonoBehaviour
{
	private static BezierTweenMgr ins;
	
	private static GameObject tweenRoot;
	private Dictionary<int, BezierTween> tweens = new Dictionary<int, BezierTween>();
	private List<BezierTween> caches = new List<BezierTween>();
	private List<BezierTween> deleteTweens = new List<BezierTween>();
	private static int increateId = 1;

	private void Awake()
	{
		ins = this;
	}
	private BezierTween GetFromPool()
	{
		BezierTween item = null;
		if (caches.Count > 0)
		{
			item = caches[caches.Count-1];
			caches.RemoveAt(caches.Count - 1);
		}
		else
			item = new BezierTween();
		return item;
	}
	private void ReturnToPool(BezierTween item)
	{
		item.Reset();
		caches.Add(item);
	}
	public static BezierTween Create(GObject target, Vector2 endPos, Vector2 control1, float time)
	{
		if (target == null) return null;
		if (tweenRoot == null)
		{
			tweenRoot = new GameObject("_tween");
			tweenRoot.AddComponent<BezierTweenMgr>();
		}
		BezierTween tween = ins.GetFromPool();
		tween.id = increateId++;
		tween.target = target;
		tween.startPos = target.xy;
		tween.endPos = endPos;
		tween.control1 = control1;
		tween.maxTime = time;
		tween.delay = 0;
		tween.accelerate = 1;
		tweenRoot.SetActive(true);
		ins.tweens.Add(tween.id, tween);
		return tween;
	}
    // Update is called once per frame
    void Update()
    {
		deleteTweens.Clear();
		foreach (var v in tweens)
		{
			var tween = v.Value;
			tween.Update(Time.deltaTime);
			if (tween.isComplete)
			{
				deleteTweens.Add(tween);
			}
		}
		for(int i = 0; i < deleteTweens.Count; i++)
		{
			var tween = deleteTweens[i];
			tweens.Remove(tween.id);
			ReturnToPool(tween);
		}
		if (tweens.Count == 0)
		{
			increateId = 1;
			tweenRoot.SetActive(false);
		}
    }
}
